from myelin.Ns import MYELINS
from myelin.server.nodetype.Transform import EventsTransform, TransformMap
from myelin.server.nodetype.Events import EventHandler

from myelin.server.core.ft import ModelDriver
from nodetypes.formats.mml import Navigator, Profiler
from nodetypes.formats import Constants

from Document import Document

XFORMS = u"http://www.w3.org/2002/xforms"

class Document(Document):
    
    newNavigator = Navigator.Navigator
    newProfiler = Profiler.AgentProfiler
    newContentDbDriver = staticmethod(ModelDriver.FromRepo)
    defaultMode = u'published'
    
    def createNav(self, context, node, locale):
        model = context.model           
        
        nxa = node.xml_append
        nxc = node.xml_create_element        
        
        nav = self.newNavigator(
            locale,
            model.rdf_initDriver(
                self.newContentDbDriver(
                    context.repo,
                    context.request.graphs[self.defaultMode]
                )
            )
        )
        
        nav.createParentNav(
            context,
            nxa(
                nxc(
                    u'a:parents', MYELINS
                )
            ),
            model
        )        
        
        nav.createTranslationNav(
            context,
            nxa(
                nxc(
                    u'a:translations', MYELINS
                )
            ),
            model
        )
                
        nav.createGroupingNav(
            context,
            nxa(
                nxc(
                    u'a:node-groupings', MYELINS
                )
            ),
            model
        )
        
        return node


class Form(object):
    
    extensionsMap = Constants.EXTENSIONS_MAP
    
    def createInstance(self, context, node):
        return node
    
    def createSubmission(self, context, node):
        node.xml_append(
            node.xml_create_element(
                u'xf:submission', XFORMS,
                attributes = {
                    u'id'       : u'main-subm',
                    u'method'   : u'post',
                    u'action'   : getattr(self,'defaultSubmitAction',context.action),
                }
            )
        )
        return node
    
    def createMethodOptions(self, context, node, methods):
        if not methods:
            return
        
        nxa = node.xml_append
        nxc = node.xml_create_element
        
        map = self.extensionsMap.get
        selected = context.method
        
        methods.sort()       
        for m in methods:
            t = map(m)
            if not t:
                continue
            if m == selected:
                nxa(
                    nxc(
                        u'a:option', MYELINS,
                        attributes={
                            u'key'      : unicode(m),                                
                            u'imt'      : t.imt,
                            u'selected' : u'1'
                        }
                    )
                )
            else:
                nxa(
                nxc(
                    u'a:option', MYELINS,
                    attributes={
                        u'key'      : unicode(m),                                
                        u'imt'      : t.imt,
                        #u'href'     : url(baseUrl, method=m)
                    }
                )
            )
                
        return node


class RedirectDocument(Document):
    
    def createDocument(self, context, source):
        doc = self.startDocument(context, source)
        
        node = doc.childNodes[0]
        
        node = node.xml_append(
            node.xml_create_element(
                u'a:head', MYELINS
            )
        )
        
        self.createAccount(
            context,                
            node.xml_append(
                node.xml_create_element(
                    u'a:account', MYELINS
                )
            ),
            context.defaults.default_locale # should this be current source's locale?
        )
        
        return doc, self.imt
    

class Document(Document):
        
    def createHead(self, context, node, locale):
        nxa = node.xml_append
        nxc = node.xml_create_element
        
        self.createAccount(
            context,
            nxa(
                nxc(
                    u'a:account', MYELINS
                )
            ),
            locale
        )
        
        self.createMethods(
            context,
            nxa(
                nxc(
                    u'a:methods', MYELINS
                )
            )
        )
        
        nxa(
            nxc(
                u'a:title', MYELINS,
                attributes={
                    u'key' : unicode(context.action),
                },
                content=context.model.rdf_join('dcTitle')
            )
        )
        
        self.createNav(
            context,
            nxa(
                nxc(
                    u'a:nav', MYELINS
                )
            ),
            locale
        )
        
        return node
        

    def createContent(self, context, node, locale):
        nodeType = context.nodeType
        args = context.request.args
        
        event = context.event
        eventData = event.data
        
        nxa = node.xml_append
        nxc = node.xml_create_element        
        
        # msgs
        msgs = eventData.msgs #or args.has_key('msg') and args.pop('msg')[0]
        if msgs:
            msgsNode = nxa(
                nxc(
                    u'a:msgs', MYELINS
                )
            )
            
            for m in msgs:
                msgsNode.xml_append(
                    msgsNode.xml_create_element(
                        u'a:msg', MYELINS,
                        attributes = {
                            u'key'      : unicode(m),
                        }
                    )
                )
            
        # form
        if hasattr(self,'formClass'):
            formNode = nxa(
                nxc(
                    u'a:form', MYELINS,
                    attributes = {
                        u'mode'     : u'main',
                        u'action'   : context.action,
                        u'event'    : unicode(event.key),
                        u'class'    : self.formClass,
                    }
                )
            )
        else:
            formNode = nxa(
                nxc(
                    u'a:form', MYELINS,
                    attributes = {
                        u'mode'     : u'main',
                        u'action'   : context.action,
                        u'event'    : unicode(event.key),
                    }
                )
            )
        
        # model
        curNode = formNode.xml_append(
            formNode.xml_create_element(
                u'xf:model', XFORMS,
                attributes = {
                    u'id'       : u'main-model',
                }
            )
        )
        cxa = curNode.xml_append
        
        if eventData.form:
            eventData.form.createInstance(
                context,
                cxa(
                    nxc(
                        u'xf:instance', XFORMS,
                        attributes = {
                            u'id'       : u'main-inst',
                        }
                    )
                ).xml_append(
                    nxc(
                        u'a:' + nodeType.typeInfo['key'], MYELINS,
                        attributes = {
                            u'node-id'      : context.sourceId,
                        }
                    )
                )
            )
            eventData.form.createSubmission(context, curNode)
            
        else:
            cxa(
                nxc(
                    u'xf:instance', XFORMS,
                    attributes = {
                        u'id'       : u'main-inst',
                    }
                )
            )
        
            cxa(
                nxc(
                    u'xf:submission', XFORMS,
                    attributes = {
                        u'id'       : u'main-subm',
                        u'method'   : u'post',
                        u'action'   : context.action,
                    }
                )
            )
        # end of model
               
        self.createSubmissionEvents(
            context,
            formNode
        )
        
        if eventData.status:
            formNode.status = eventData.status
            if eventData.status_type:
                formNode.xml_set_attribute(
                    (u'status-type',None),
                    eventData.status_type
                )
                    
            
        return node
    
    
    def createSubmissionEvents(self, context, node):
        eventData = context.event.data
        curNode = node.xml_append(
            node.xml_create_element(
                u'a:submission', MYELINS,
                attributes = {
                    u'name'     : u'event',
                    u'bind'     : u'main-subm',
                    u'stage'    : unicode(eventData.stage or 0),
                }
            )
        )
        
        s = eventData.submits
        if s:
            cxa = curNode.xml_append
            cxc = curNode.xml_create_element
            for k in s:
                cxa(
                    cxc(
                        u'a:submit', MYELINS,
                        attributes = {
                            u'key'      : unicode(k),
                        }
                    )
                )
            
        return node


class EventHandler(EventHandler):
    
    newRedirectDocument = RedirectDocument
    newDocument = Document    
    

class ResetEventHandler(EventHandler):
    
    newResetForm        = Form
    
    def process(self, context, source):
        eventData = context.event.data
        
        eventData.status = u'success'
        eventData.status_type = u'reset-success'
        eventData.form = self.newResetForm()        
        eventData.stage = 0
        eventData.submits = context.transform.submitEvents[0]
        
        if not context.model:
            context.model = context.nodeType.retrieveModel(context)
        
        return self.newDocument().createDocument(context, source)
    

class CloseEventHandler(EventHandler):
    
    def process(self, context, source):
        return self.newRedirectDocument().createDocument(context, source)
    
class ParentNodeGetter:
    
    def __init__(self, locale):
        self.locale = locale
    
    def getParentNode(self, context, model=None):
        model = model or context.model
        defaults = context.server.defaults
        roots = defaults.root_id,
            
        p = filter(
            lambda n: n.rdf_value != roots,
            model.mParent
        )
        #p = model.mParent
        for p in self.filterNodesByLocale(
            context,
            p
        ):
            yield p
            
        # if model is a translation of another node,
        # there may exists a parent node in the same locale
        for p in model.mTranslation_Of:
            for p in p.mParent:
                p = p.mTranslation
                if p:
                    for p in self.filterNodesByLocale(
                        context,
                        p
                    ):
                        yield p
        
    def filterNodesByLocale(self, context, models):
        locale = self.locale
        for n in models:
            if locale in n.dcLanguage:
                yield n
            else:
                for t in n.mTranslation:
                    if locale in t.dcLanguage:
                        yield t
                for t in n.mTranslation_Of:
                    if locale in t.dcLanguage:
                        yield t
    

class CancelEventHandler(EventHandler):
    
    newParentNodeGetter = ParentNodeGetter
    
    def getLocale(self, context):
        for locale in context.model.dcLanguage:
            return locale.rdf_value
        else:
            return context.defaults.default_locale
    
    def process(self, context, source):
        path, query = context.session.getReferrer(context.request)
        if path == '/node/' or context.request.path == path:
            context.model = context.nodeType.retrieveModel(
                context
            ).rdf_prefetch()
            p = self.newParentNodeGetter(self.getLocale(context))
            for p in p.getParentNode(context):
                url = context.urlFormatter.getPublicUrl(p.rdf_domain,True,context.method)
                context.response_uri = "%s?no-referrer=1" % (url or '/?no-referrer=1')
                break
            else:
                context.response_uri = "%s?no-referrer=1" % getattr(context.defaults,'public_root_path','/?no-referrer=1')
        else:
            context.response_uri = query and '%s?%s&no-referrer=1' % (path,query) or '%s?no-referrer=1' % path
        return '', 'text/plain'
    
    
